<!--
 * @Description: 
 * @Author: ldx
 * @Date: 2023-03-02 21:05:41
 * @LastEditors: ldx
 * @LastEditTime: 2023-05-03 20:27:07
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>
  <script id="vertex" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform mat4 u_viewMatrix;
    uniform mat4 u_projectMatrix;
    void main(){
      // 顶点位置
      gl_Position = u_projectMatrix * u_viewMatrix * a_Position;
    }
  </script>
  <script id="fragment" type="x-shader/x-fragment">
    void main(){
      // 片元颜色
      gl_FragColor = vec4(1,0,0,1);
    }
  </script>
  <canvas id="canvas"></canvas>
  <script type="module">
    import { initProgram } from '../jsm/utils.js'
    import { Matrix4, Vector3, Vector4, Quaternion } from 'https://unpkg.com/three/build/three.module.js';
    const canvas = document.querySelector('#canvas')
    // 设置canvas容器的宽高
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight
    // 获取webgl上下文
    const gl = canvas.getContext('webgl');
    // 声明将来用来清空绘图区的颜色。分别对应r,g,b,a
    gl.clearColor(0, 0, 0, 1)
    // 使用之前声明的颜色，清空绘图区
    gl.clear(gl.COLOR_BUFFER_BIT)

    // 初始化程序对象
    initProgram(gl)

    // 声明顶点数据
    const verticeLib = [
      1.0, 1.0, 1.0,
      -1.0, 1.0, 1.0,
      -1.0, -1.0, 1.0,
      1.0, -1.0, 1.0,
      1.0, -1.0, -1.0,
      1.0, 1.0, -1.0,
      -1.0, 1.0, -1.0,
      -1.0, -1.0, -1.0,
    ];
    // 声明索引
    const indices = [
      0, 1,
      1, 2,
      2, 3,
      3, 0,

      0, 5,
      1, 6,
      2, 7,
      3, 4,

      4, 5,
      5, 6,
      6, 7,
      7, 4
    ];

    const arr = [];
    indices.forEach(n => {
      const i = n * 3
      arr.push(
        verticeLib[i] / 5,
        verticeLib[i + 1] / 5,
        verticeLib[i + 2] / 5,
      )
    })
    const vertices = new Float32Array(arr)
    
    // 创建缓冲区
    const vertexBuffer = gl.createBuffer()
    // 绑定缓冲区
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
    // 写入缓冲数据
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

    // 获取attribute变量并修改
    const a_Position = gl.getAttribLocation(gl.program, 'a_Position')
    // 修改attribute变量
    gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0)

    // 获取uniform变量
    const u_viewMatrix = gl.getUniformLocation(gl.program, 'u_viewMatrix')
    const u_projectMatrix = gl.getUniformLocation(gl.program, 'u_projectMatrix')
    
    // 启用当前绑定缓冲区的顶点数组
    gl.enableVertexAttribArray(a_Position)


    const position = new Vector3(0.2,0.2,0.8)
    const target = new Vector3(0,0,0)
    const up = new Vector3(0,1,0)
    const viewMatrix = getViewMatrix(position,target,up)
    const projectMatrix = getProjectMatrix(-2,2,2,-2,-0.3,4)
    gl.uniformMatrix4fv(u_viewMatrix, false, viewMatrix)
    gl.uniformMatrix4fv(u_projectMatrix, false, projectMatrix)
    render()

    function render(){
      // 使用之前声明的颜色，清空绘图区
      gl.clear(gl.COLOR_BUFFER_BIT)
      // 绘制一系列三角形
      gl.drawArrays(gl.LINES, 0, vertices.length/3)
    }
    // 视图矩阵
    function getViewMatrix(e,t,u){
      // 位移到原点
      const mt = new Matrix4().makeTranslation(-e.x,-e.y,-e.z)
      // 相机位置 - 目标位置，得到z轴正坐标（视线向量）
      const c = new Vector3().subVectors(e,t).normalize()
      // 上方向向量叉乘视线向量，得到x轴正坐标
      const a = new Vector3().crossVectors(u,c).normalize()
      // 视线分量叉乘x轴分量，得到y轴正坐标
      const b = new Vector3().crossVectors(c,a).normalize()
      // 正交矩阵的逆矩阵就是其转置矩阵。
      const mr = new Matrix4().set(
        ...a,0,
        ...b,0,
        -c.x,-c.y,-c.z,0,
        0,0,0,1
      )
      // 先平移在旋转
      return mr.multiply(mt).elements
    }
    
    // 获取投影矩阵
    function getProjectMatrix(left,right,top,bottom,near,far){
      const halfx = (left+right) / 2
      const halfy = (top+bottom) / 2
      const halfz = (near+far) / 2
      const mt = new Matrix4().makeTranslation(-halfx,-halfy,-halfz)
      const ms = new Matrix4().makeScale(2/(right-left),2/(top-bottom),2/(far-near))
      return ms.multiply(mt).elements
    }
    let angle = 0
    !(function ani(){
      angle+=1
      if(angle >= 360){
        angle = 0
      }
      const rad = Math.PI * angle / 180
      const x = 0.4 * Math.cos(rad) - 0.2 * Math.sin(rad)
      const z = 0.4 * Math.cos(rad) + 0.2 * Math.sin(rad)
      position.x = x
      position.z = z
      const viewMatrix = getViewMatrix(position,target,up)
      // gl.uniformMatrix4fv(u_viewMatrix, false, viewMatrix)
      render()
      requestAnimationFrame(ani)
    })()
    
  </script>
</body>

</html>